Cruyun's Blog


Talk is cheap, show you my code


系统级 I/O

文件

Unix I/O

创建的每个进程开始有三个打开的文件:标准输入 stdin(描述符为0)、标准输出 stdout(描述符为1)、标准错误 stderr(描述符为2)

Linux文件类型:

  • 普通文件 regular file

    • 文本文件 text file
    • 二进制文件 binary file
  • 目录 diretory

  • 套接字 socket:用来与另一个进程进行跨网络通行的文件,从Linux角度来看,是一个有相应描述符的打开文件

打开和关闭文件: open函数

open 函数将 filename 转换为一个文件描述符,并且返回描述符数字(总是在进程中当前没有打开的最小描述符)。

1
int open(char *filename, int flags, mode_t mode)

成功则返回新文件描述符(正整数),出错为-1。所以用户通过 open 能够打开的文件得到的文件描述符的最小编号是3。

flags 参数是一个或更多位掩码的或,是用于指定打开文件操作模式的枚举常量。

参数 意义
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 若不存在创建一个截断的空文件
O_TRUNC 若文件已存在就截断
O_APPEND 每次写之前将文件位置到文件结尾

mode_t mode 是文件权限标志,mode_t 类型指一个无符号八进制数,mode 称为 umask 变量。

关闭文件使用描述符即可关闭.

int close(int fd)

RIO提供的读写函数

RIO(Robust I/O,健壮的 I/O)包。RIO 包中有专门的数据结构为每一个文件描述符都分配了相应的独立的读缓冲区,这样不同线程对不同文件描述符的读访问也就不会出现并发问题。

  • 无缓冲的输入输出函数rio_readnrio_writen

    rio_readn 函数

    • 从描述符 fd 的当前文件位置最多传送 n 个字节到内存位置 usrbuf;
    • 在遇到EOF 只能返回一个不足值。

    rio_writen 函数

    • 从内存位置 usrbuf 传送 n 个字节到描述符 fd;
    • 不返回不足值

对同一个描述符,可以任意调用rio_readnrio_writen函数。

  • 带缓冲的输入输出函数rio_readlinebrio_readnb

    rio_readlineb

    • 从一个内部读缓冲区复制一个文本行,当缓冲区变空时,会自动调用 read 重新填满缓冲区。

    rio_readnb

    • 用于既包含文本行也包含二进制数据的文件(如 HTTP 响应)
    • 是 rio_readln 的带缓冲版本

      rio_read

    • RIO 程序的核心函数

    • 是 Linux read 函数的带缓冲版本。

从标准输入复制一个文本文件到标准输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "csapp.h"
int main
{
int n;
rio_t rio;
char buf[MAXLINE];
// 将描述符 fd 与地址 rp(文件) 处的一个类型为 rio_t 的读缓冲区联系起来
Rio_readinitb(&rio, STDIN_FIFENO);
// 从文件读取下一个文本行,将它复制到内存位置 buf,
while(n = Rio_readlineb(&rio, buf, MAXLINE) != 0)
Rio_writen(STDIN_FIFENO, buf, n);
}

读取文件元数据

应用程序调用 statfstat函数,检索文件元数据

  1. int stat(const char* filename, struct stat *buf)
  1. int fast(int fd, struct *buf)